import OSS from 'ali-oss';
import { createHash } from 'crypto';
import fs from 'fs';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';

import { Readable } from 'stream';

// 配置OSS客户端
const client = new OSS({
    region: process.env.OSS_REGION,
    accessKeyId: process.env.OSS_AK,
    accessKeySecret: process.env.OSS_SK,
    bucket: process.env.OSS_BUCKET
});

function calculateMD5(fileBuffer) {
    // 创建一个用于 MD5 加密的 Hash 对象
    const hash = createHash('md5');
    // 读取 Buffer 数据并计算散列值
    hash.update(fileBuffer);
    // 返回16进制形式的散列值
    return hash.digest('hex');
}

export async function getFileBuffer(fileName) {
    // 检查OSS中该文件是否已存在
    const objectName = `funds/gpt/${fileName}`;
    let exist = false;
    try {
        await client.head(objectName);
        exist = true;
    } catch (err) {
        if (err.code !== 'NoSuchKey') {
            throw err;
        }
    }

    // 返回公开URL
    if (exist) {
        try {
            // 获取文件内容
            const result = await client.get(objectName);
            // result.contents 是一个Readable Stream，需要转换为Buffer
            const buffer = await new Promise((resolve, reject) => {
              const chunks = [];
              result.contents.on('data', (chunk) => {
                chunks.push(chunk);
              });
              result.contents.on('end', () => {
                resolve(Buffer.concat(chunks));
              });
              result.contents.on('error', (err) => {
                reject(err);
              });
            });
            return buffer;
          } catch (error) {
            console.error('Error getting object from OSS:', error);
            throw error;
          }
    }

    return null;
}

export async function uploadLocalFile(localFilePath) {
    // 检查OSS中该文件是否已存在
    const fileName = `${uuidv4()}_${path.basename(localFilePath)}`
    const fileStream = fs.createReadStream(localFilePath);
    const objectName = `funds/gpt/${fileName}`;
    let exist = false;
    try {
        await client.head(objectName);
        exist = true;
    } catch (err) {
        if (err.code !== 'NoSuchKey') {
            throw err;
        }
    }

    // 如果文件已存在，则不上传
    if (!exist) {
        await client.put(objectName, fileStream, {
            headers: {
                'x-oss-object-acl': 'public-read' // 设置文件为公开读权限
            }
        });
    }

    // 返回公开URL
    return client.generateObjectUrl(objectName);
}

export async function uploadPublicFileByMd5(userId, file) {
    const buffer = await file.toBuffer();
    const fileName = calculateMD5(buffer);
    const userObjectName = `funds/gpt/${userId}.jpg`;
    const objectName = `funds/gpt/${fileName}.jpg`;

    // 检查OSS中该文件是否已存在
    let exist = false;
    try {
        await client.head(userObjectName);
        await client.head(objectName);
        exist = true;
    } catch (err) {
        if (err.code !== 'NoSuchKey') {
            throw err;
        }
    }

    // 如果文件已存在，则不上传
    if (!exist) {
        await client.put(userObjectName, await file.toStream(), {
            headers: {
                'x-oss-object-acl': 'public-read' // 设置文件为公开读权限
            }
        });
        await client.put(objectName, await file.toStream(), {
            headers: {
                'x-oss-object-acl': 'public-read' // 设置文件为公开读权限
            }
        });
    }

    // 返回公开URL
    return client.generateObjectUrl(userObjectName);
}

export async function uploadPngFileByBuffer(fileName, buffer) {
    try {
        const objectName = `funds/gpt/${fileName}`;
        await client.put(objectName, bufferToStreamAsync(buffer), {
            headers: {
                'x-oss-object-acl': 'public-read' // 设置文件为公开读权限
            }
        });

        // 返回公开URL
        return client.generateObjectUrl(objectName);
    } catch (error) {
        console.error('转换SVG到PNG时发生错误:', error);
        throw error;
    }
}

function bufferToStreamAsync(buffer) {
    // 创建一个Readable Stream实例
    const stream = new Readable({
        read() { } // 不需要从外部源读取数据，因此read函数为空
    });

    // 异步推送数据到流中
    setImmediate(() => {
        stream.push(buffer);
        stream.push(null);
    });

    return stream;
}

